home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / help.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  13KB  |  575 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include <X11/Shell.h>
  17. #include <X11/Xaw/Command.h>
  18. #include <X11/Xaw/Toggle.h>
  19. #include <X11/Xaw/Form.h>
  20. #include <X11/Xaw/Label.h>
  21. #include <X11/Xaw/List.h>
  22. #include <X11/Xaw/AsciiText.h>
  23. #include <X11/Xaw/Text.h>
  24. #include <X11/Xaw/Viewport.h>
  25. #include <X11/Xaw/Scrollbar.h>
  26. #include <X11/StringDefs.h>
  27. #include <stdio.h>
  28. #include <ctype.h>
  29.  
  30. #include "misc.h"
  31.  
  32. #define TAB_DISTANCE    4
  33.  
  34. static String helpText[] = {
  35. #include "Help.txt.h"
  36. };
  37.  
  38. typedef struct HelpInfo_s {
  39.     char            *name, *topic;
  40.     int            index;
  41.     int            start, stop;
  42.     struct HelpInfo_s    *next;
  43. } HelpInfo;
  44.  
  45. typedef struct {
  46.     Widget        shell;
  47.     int        curTopic;
  48.     Widget        topicList, topicPort;
  49.     Widget        textText, textTitle;
  50.     Widget        nextButton, prevButton;
  51.     Widget        scrollbar;
  52.     int        ninfo;
  53.     String        *topics;
  54.     HelpInfo    *info;
  55. } LocalInfo;
  56.  
  57. static Widget    toplevel;
  58.  
  59. /*
  60. **  Build heirarchitcal help information structures.
  61. */
  62. char *matchGet(char *line, char *pat)
  63. {
  64.     static char    buf[256];
  65.     int        len = strlen(pat);
  66.     char        *sp, *ep;
  67.  
  68.     if (strncmp(line, pat, len) != 0) 
  69.         return NULL;
  70.  
  71.     for (sp = line + len; isspace(*sp); sp++);
  72.     for (ep = sp; isalnum(*ep); ep++);
  73.     strncpy(buf, sp, ep - sp);
  74.     buf[ep-sp] = '\0';
  75.  
  76.     return buf;
  77. }
  78.  
  79. static HelpInfo    *buildInfo(int *count)
  80. {
  81.     Boolean        nc, flg;
  82.     int        depth = 0, stop = -1;
  83.     int        i, j;
  84.     char        parts[10][20];
  85.     HelpInfo    *head = NULL, **nxt = &head, *cur = NULL;
  86.     char        *cp, *tp = NULL;
  87.     int        idx = 0;
  88.  
  89.     if (count != NULL)
  90.         *count = 0;
  91.  
  92.     for (i = 0; i < XtNumber(helpText); i++) {
  93.         flg = nc = False;
  94.         if ((cp = matchGet(helpText[i], "#BEGIN")) != NULL) {
  95.             int    argc;
  96.             char    *argv[128];
  97.             char    buf[256];
  98.  
  99.             nc = True;
  100.             strcpy(buf, helpText[i]);    /* Need R&W buffer */
  101.             StrToArgv(buf, &argc, argv);
  102.             strcpy(parts[depth], argv[1]);
  103.             tp = (argc > 2) ? argv[2] : argv[1];
  104.         } else if ((cp = matchGet(helpText[i], "#PUSH")) != NULL) {
  105.             depth++;
  106.             flg = True;
  107.         } else if ((cp = matchGet(helpText[i], "#POP")) != NULL) {
  108.             if (depth > 0)
  109.                 depth--;
  110.             flg = True;
  111.         } else if ((cp = matchGet(helpText[i], "#NL")) != NULL) {
  112.             stop = i;
  113.         } else {
  114.             stop = i;
  115.         }
  116.  
  117.         if (nc) {
  118.             int    len;
  119.  
  120.             if (cur != NULL) {
  121.                 cur->stop = stop + 1;
  122.                 *nxt = cur;
  123.                 nxt = &cur->next;
  124.             }
  125.             
  126.  
  127.             cur = XtNew(HelpInfo);
  128.             cur->index = idx++;
  129.             cur->start = i + 1;
  130.             cur->next = NULL;
  131.  
  132.             if (count != NULL)
  133.                 (*count)++;
  134.         
  135.             len = 0;
  136.             for (j = 0; j <= depth; j++)
  137.                 len += strlen(parts[j]) + 1;
  138.             cur->name = (char*)XtMalloc(len + 1);
  139.             cur->name[0] = '\0';
  140.             for (j = 0; j <= depth; j++) {
  141.                 strcat(cur->name, parts[j]);
  142.                 strcat(cur->name, ".");
  143.             }
  144.             cur->name[strlen(cur->name)-1] = '\0';
  145.             cur->topic = (char*)XtMalloc(strlen(tp) + 7 + 2 * depth);
  146.             for (j = 0; j < depth * 2; j++)
  147.                 cur->topic[j] = ' ';
  148.             cur->topic[j] = '\0';
  149.             strcat(cur->topic, tp);
  150.             strcat(cur->topic, "  ");
  151.         } else if (flg) {
  152.             if (cur->start == i)
  153.                 cur->start++;
  154.         }
  155.     }
  156.  
  157.     if (cur != NULL) {
  158.         cur->stop = i;
  159.         *nxt = cur;
  160.         nxt = &cur->next;
  161.     }
  162.  
  163.     return head;
  164. }
  165.  
  166.  
  167. static void doneCB(Widget w, XtPointer lArg, XtPointer junk)
  168. {
  169.     LocalInfo    *l = (LocalInfo*)lArg;
  170.  
  171.     XtPopdown(l->shell);
  172. }
  173.  
  174. static char *buildText(HelpInfo *cur)
  175. {
  176.     int        i, len;
  177.     char        *txt;
  178.     char        *tp, *cp;
  179.  
  180.     len = 0;
  181.     for (i = cur->start; i < cur->stop; i++) 
  182.         len += strlen(helpText[i]) + 2;
  183.     
  184.     tp = txt = (char*)XtCalloc(len + 8, sizeof(char));
  185.     for (i = cur->start; i < cur->stop; i++) {
  186.         /*
  187.         **  Line of all whitespace is a paragraph break.
  188.         */
  189.         for (cp = helpText[i]; *cp != '\0'; cp++)
  190.             if (!isspace(*cp))
  191.                 break;
  192.         if (*cp == '\0') {
  193.             *tp++ = '\n';
  194.             *tp++ = '\n';
  195.             continue;
  196.         }
  197.         if (strncmp(helpText[i], "#NL", 3) == 0) {
  198.             *tp++ = '\n';
  199.             continue;
  200.         }
  201.         for (cp = helpText[i]; *cp != '\0'; *tp++ = *cp++);
  202.         *tp++ = ' ';
  203.     }
  204.     *tp++ = '\n';
  205.     *tp = '\0';
  206.  
  207.     return txt;
  208. }
  209.  
  210. static void display(LocalInfo *l, HelpInfo *cur)
  211. {
  212.     char    *txt;
  213.     float    self, top, shown;
  214.  
  215.     if (cur == NULL)
  216.         cur = l->info;
  217.  
  218.     l->curTopic = cur->index;
  219.  
  220.     txt = buildText(cur);
  221.  
  222.     XtVaSetValues(l->textText, XtNstring, txt, NULL);
  223.     XtVaSetValues(l->textTitle, XtNlabel, cur->topic, NULL);
  224.  
  225.     XtFree((XtPointer)txt);
  226.  
  227.     XtVaSetValues(l->nextButton, XtNsensitive, (cur->next != NULL), NULL);
  228.     XtVaSetValues(l->prevButton, XtNsensitive, (cur->index != 0), NULL);
  229.  
  230.     XtCallActionProc(l->textText, "beginning-of-file", NULL, NULL, 0);
  231.  
  232.     /*
  233.     **  Now position the scrollbar to be visible
  234.     */
  235.  
  236.     XtVaGetValues(l->scrollbar, XtNtopOfThumb, &top, 
  237.                     XtNshown, &shown, 
  238.                     NULL);
  239.     self = (float)cur->index / (float)l->ninfo;
  240.     if (self < top || self > top + shown) {
  241.         static String    args[] = { "Forward" };
  242.         top = self - shown / 2.0;
  243.         if (top < 0.0)
  244.             top = 0.0;
  245.         if (top + shown > 1.0)
  246.             top = 1.0 - shown;
  247.  
  248.         /*
  249.         **  Scrollbar doesn't notify on a SetThumb()
  250.         **    So we must do it
  251.         */
  252.         XawScrollbarSetThumb(l->scrollbar, top, -1.0);
  253.         XtCallCallbacks(l->scrollbar, XtNjumpProc, (XtPointer)&top);
  254.     }
  255. }
  256.  
  257. static void topicCB(Widget w, LocalInfo *l, XawListReturnStruct *list)
  258. {
  259.     HelpInfo    *cur = l->info;
  260.     int        i;
  261.  
  262.     for (i = 0; i < list->list_index; i++)
  263.         cur = cur->next;
  264.  
  265.     display(l, cur);
  266. }
  267. static void downCB(Widget w, LocalInfo *l, XtPointer junk)
  268. {
  269.     XtCallActionProc(l->textText, "next-page", NULL, NULL, 0);
  270. }
  271. static void upCB(Widget w, LocalInfo *l, XtPointer junk)
  272. {
  273.     XtCallActionProc(l->textText, "previous-page", NULL, NULL, 0);
  274. }
  275. static void prevCB(Widget w, LocalInfo *l, XtPointer junk)
  276. {
  277.     XawListReturnStruct    lrs;
  278.  
  279.     if (l->curTopic == 0)
  280.         return;
  281.  
  282.     lrs.list_index = l->curTopic - 1;
  283.     XawListHighlight(l->topicList, lrs.list_index);
  284.     topicCB(w, l, &lrs);
  285. }
  286. static void nextCB(Widget w, LocalInfo *l, XtPointer junk)
  287. {
  288.     XawListReturnStruct    lrs;
  289.  
  290.     if (l->curTopic == l->ninfo - 1)
  291.         return;
  292.  
  293.     lrs.list_index = l->curTopic + 1;
  294.     XawListHighlight(l->topicList, lrs.list_index);
  295.     topicCB(w, l, &lrs);
  296. }
  297.  
  298. static LocalInfo *buildPopup(LocalInfo *l, Widget parent)
  299. {
  300.     Widget        shell, form;
  301.     Widget        title;
  302.     Widget        topicList, topicPort;
  303.     Widget        textTitle, textList;
  304.     Widget        done, prev, next;
  305.     Widget        pgDown, pgUp;
  306.  
  307.     if (l == NULL) {
  308.         HelpInfo    *cur;
  309.         int        i;
  310.  
  311.         l = XtNew(LocalInfo);
  312.         l->info = buildInfo(&l->ninfo);
  313.  
  314.         l->topics = (String *)XtCalloc(l->ninfo + 1, sizeof(String));
  315.         for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
  316.             l->topics[i] = cur->topic;
  317.         l->topics[i] = NULL;
  318.         l->shell = None;
  319.     }
  320.  
  321.     if (l->shell != None)
  322.         return l;
  323.  
  324.         shell = XtVaCreatePopupShell("helpDialog",
  325.                         topLevelShellWidgetClass, GetShell(parent),
  326.                         NULL);
  327.  
  328.         form = XtVaCreateManagedWidget("form",
  329.                                 formWidgetClass, shell,
  330.                                 XtNborderWidth, 0,
  331.                                 NULL);
  332.  
  333.     title = XtVaCreateManagedWidget("title",
  334.                 labelWidgetClass, form,
  335.                                 XtNborderWidth, 0,
  336.                 XtNtop, XtChainTop,
  337.                 XtNbottom, XtChainTop,
  338.                 XtNleft, XtChainLeft,
  339.                 XtNright, XtChainLeft,
  340.                 NULL);
  341.  
  342.     /*
  343.     **
  344.     */
  345.     topicPort = XtVaCreateManagedWidget("topicPort",
  346.                 viewportWidgetClass, form,
  347.                 XtNtop, XtChainTop,
  348.                 XtNbottom, XtChainBottom,
  349.                 XtNleft, XtChainLeft,
  350.                 XtNright, XtChainLeft,
  351.                 XtNfromVert, title,
  352.                 XtNallowVert, True,
  353.                 XtNforceBars, True,
  354.                 NULL);
  355.     topicList = XtVaCreateManagedWidget("topic", 
  356.                 listWidgetClass, topicPort,
  357.                 XtNverticalList, True,
  358.                 XtNforceColumns, True,
  359.                 XtNdefaultColumns, 1,
  360.                 NULL);
  361.  
  362.     /*
  363.     **
  364.     */
  365.     textTitle = XtVaCreateManagedWidget("textTitle",
  366.                 labelWidgetClass, form,
  367.                                 XtNborderWidth, 0,
  368.                 XtNfromHoriz, topicPort,
  369.                 XtNfromVert, title,
  370.                 XtNleft, XtChainLeft,
  371.                 XtNright, XtChainRight,
  372.                 XtNtop, XtChainTop,
  373.                 XtNbottom, XtChainTop,
  374.                 XtNresize, False,
  375.                 NULL);
  376.  
  377.     textList = XtVaCreateManagedWidget("textText", 
  378.                 asciiTextWidgetClass, form,
  379.                 XtNwrap, XawtextWrapWord,
  380.                 XtNtop, XtChainTop,
  381.                 XtNbottom, XtChainBottom,
  382.                 XtNleft, XtChainLeft,
  383.                 XtNright, XtChainRight,
  384.                 XtNfromVert, textTitle,
  385.                 XtNfromHoriz, topicPort,
  386.                 XtNscrollVertical, XawtextScrollAlways,
  387.                 XtNdisplayCaret, False,
  388.                 NULL);
  389.     {
  390.         Widget    sink;
  391.         int    tabs[10];
  392.         int    i;
  393.  
  394.         for (i = 0; i < XtNumber(tabs); i++) 
  395.             tabs[i] = i * TAB_DISTANCE;
  396.  
  397.         XtVaGetValues(textList, XtNtextSink, &sink, NULL);
  398.  
  399.         XawTextSinkSetTabs(sink, XtNumber(tabs), tabs);
  400.     }
  401.  
  402.     /*
  403.     **
  404.     */
  405.     done = XtVaCreateManagedWidget("done", 
  406.                 commandWidgetClass, form,
  407.                 XtNfromVert, textList,
  408.                 XtNtop, XtChainBottom,
  409.                 XtNbottom, XtChainBottom,
  410.                 XtNleft, XtChainLeft,
  411.                 XtNright, XtChainLeft,
  412.                 NULL);
  413.     next = XtVaCreateManagedWidget("next", 
  414.                 commandWidgetClass, form,
  415.                 XtNfromVert, textList,
  416.                 XtNfromHoriz, done,
  417.                 XtNtop, XtChainBottom,
  418.                 XtNbottom, XtChainBottom,
  419.                 XtNleft, XtChainLeft,
  420.                 XtNright, XtChainLeft,
  421.                 NULL);
  422.     prev = XtVaCreateManagedWidget("prev", 
  423.                 commandWidgetClass, form,
  424.                 XtNfromVert, textList,
  425.                 XtNfromHoriz, next,
  426.                 XtNtop, XtChainBottom,
  427.                 XtNbottom, XtChainBottom,
  428.                 XtNleft, XtChainLeft,
  429.                 XtNright, XtChainLeft,
  430.                 NULL);
  431.     pgDown = XtVaCreateManagedWidget("down", 
  432.                 commandWidgetClass, form,
  433.                 XtNfromVert, textList,
  434.                 XtNfromHoriz, topicPort,
  435.                 XtNtop, XtChainBottom,
  436.                 XtNbottom, XtChainBottom,
  437.                 XtNleft, XtChainLeft,
  438.                 XtNright, XtChainLeft,
  439.                 NULL);
  440.     pgUp = XtVaCreateManagedWidget("up", 
  441.                 commandWidgetClass, form,
  442.                 XtNfromVert, textList,
  443.                 XtNfromHoriz, pgDown,
  444.                 XtNtop, XtChainBottom,
  445.                 XtNbottom, XtChainBottom,
  446.                 XtNleft, XtChainLeft,
  447.                 XtNright, XtChainLeft,
  448.                 NULL);
  449.  
  450.     l->shell     = shell;
  451.     l->textText  = textList;
  452.     l->textTitle = textTitle;
  453.     l->topicPort = topicPort;
  454.     l->topicList = topicList;
  455.     l->nextButton = next;
  456.     l->prevButton = prev;
  457.     l->scrollbar  = XtNameToWidget(topicPort, "vertical");
  458.  
  459.     XawListChange(topicList, l->topics, 0, 0, True);
  460.  
  461.     XtAddCallback(topicList, XtNcallback, (XtCallbackProc)topicCB, (XtPointer)l);
  462.     XtAddCallback(pgDown, XtNcallback, (XtCallbackProc)downCB, (XtPointer)l);
  463.     XtAddCallback(pgUp, XtNcallback, (XtCallbackProc)upCB, (XtPointer)l);
  464.     XtAddCallback(next, XtNcallback, (XtCallbackProc)nextCB, (XtPointer)l);
  465.     XtAddCallback(prev, XtNcallback, (XtCallbackProc)prevCB, (XtPointer)l);
  466.  
  467.     XtAddCallback(done, XtNcallback, doneCB, (XtPointer)l);
  468.     AddDestroyCallback(shell, (void (*)(Widget, void *, XEvent *))doneCB, (XtPointer)l);
  469.  
  470.     return l;
  471. }
  472.  
  473. void HelpDialog(Widget parent, String name)
  474. {
  475.     static LocalInfo    *l = NULL;
  476.     int            i;
  477.     HelpInfo        *cur;
  478.  
  479.     l = buildPopup(l, toplevel);
  480.  
  481.     for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
  482.         if (strcmp(name, cur->name) == 0)
  483.             break;
  484.  
  485.     if (!XtIsRealized(l->shell))
  486.         display(l, cur);
  487.  
  488.     XawListHighlight(l->topicList, cur == NULL ? 0 : i);
  489.  
  490.     XtPopup(l->shell, XtGrabNone);
  491.  
  492.     display(l, cur);
  493.     XMapRaised(XtDisplay(l->shell), XtWindow(l->shell));
  494. }
  495.  
  496. void HelpTextOutput(FILE *fd, String name)
  497. {
  498.     char        *txt;
  499.     int        col, wlen, i;
  500.     char        *tp, *cp, *wstart;
  501.     HelpInfo    *head, *cur;
  502.  
  503.     head = buildInfo(NULL);
  504.  
  505.     for (i = 0, cur = head; cur != NULL; cur = cur->next, i++)
  506.         if (strcmp(name, cur->name) == 0)
  507.             break;
  508.  
  509.     if (cur == NULL)
  510.         return;
  511.  
  512.     txt = buildText(cur);
  513.  
  514.     col = wlen = 0;
  515.     for (tp = txt; *tp != '\0'; tp++) {
  516.         if (isspace(*tp) || *tp == '\n') {
  517.             for (i = 0; i < wlen; i++, wstart++)
  518.                 putc(*wstart, fd);
  519.             col += wlen;
  520.             wlen = 0;
  521.             if (*tp == '\t') {
  522.                 do {
  523.                     putc(' ', fd);
  524.                     col++;
  525.                 } while (col % TAB_DISTANCE != 0);
  526.             } else if (*tp == '\n') {
  527.                 putc(*tp, fd);
  528.                 col = 0;
  529.             } else {
  530.                 putc(*tp, fd);
  531.                 col++;
  532.             }
  533.  
  534.             if (col > 75) {
  535.                 putc('\n', fd);
  536.                 col = 0;
  537.             }
  538.         } else if (wlen != 0) {
  539.             if (col != 0 && (wlen + col > 75)) {
  540.                 putc('\n', fd);
  541.                 col = 0;
  542.             }
  543.             wlen++;
  544.         } else {
  545.             wlen = 1;
  546.             wstart = tp;
  547.         }
  548.     }
  549.     for (i = 0; i < wlen; i++, wstart++)
  550.         putc(*wstart, fd);
  551.     if (col != 0)
  552.         putc('\n', fd);
  553.  
  554.     XtFree((XtPointer)txt);
  555. }
  556.  
  557. static void helpAction(Widget w, XEvent *event, String *prms, Cardinal *nprms)
  558. {
  559.     if (*nprms != 1) {
  560.         fprintf(stderr,"Help called with wrong number of params\n");
  561.         return;
  562.     }
  563.  
  564.     HelpDialog(w, prms[0]);
  565. }
  566.  
  567. void HelpInit(Widget top)
  568. {
  569.         static XtActionsRec     act = { "PaintHelp", (XtActionProc)helpAction };
  570.  
  571.         XtAppAddActions(XtWidgetToApplicationContext(top), &act, 1);
  572.  
  573.     toplevel = top;
  574. }
  575.